package dream_lab.io

import kotlinx.cinterop.*
import libuv.*

open class UvLoop {
    private val _isDefaultLoop: Boolean
    internal val _ptr: CPointer<uv_loop_t>
    private constructor(ptr: CPointer<uv_loop_t>, isDefaultLoop: Boolean) {
        this._ptr = ptr
        this._isDefaultLoop = isDefaultLoop
    }
    constructor() : this( nativeHeap.alloc<uv_loop_t>().ptr, false)
    companion object {
        val default by lazy { UvLoop(uv_default_loop()!!, true) }
    }
    fun run() {
        uv_run(this._ptr, UV_RUN_DEFAULT).let(UvException::throwIfErrorHappens)
    }
    fun dispose() {
        if (this._isDefaultLoop) return
        nativeHeap.free(this._ptr.rawValue)
    }
}
fun UvLoop.runInterval(periodic: Int, action: (timer: UvTimer) -> Unit){
    val timer = UvTimer(this, action)
    timer.start(periodic, periodic)
}
open class UvTimer(val loop: UvLoop, private val action: (timer: UvTimer) -> Unit) {
    private var _ref: StableRef<UvTimer>? = null
    internal val _ptr = nativeHeap.alloc<uv_timer_t> {}.ptr
    init {
        uv_timer_init(loop._ptr, this._ptr).let(UvException::throwIfErrorHappens)
    }
    private fun dispose() {
        this._ref?.dispose()
        nativeHeap.free(this._ptr)
    }
    fun start(periodic: Int, repeat: Int) {
        this._ref = StableRef.create(this)
        this._ptr.pointed.data = _ref!!.asCPointer()
        uv_timer_start(this._ptr, staticCFunction {_timerPtr ->
            _timerPtr!![0].data!!.asStableRef<UvTimer>().get().fire()
        }, periodic.toULong(), repeat.toULong()).let(UvException::throwIfErrorHappens)
    }
    private fun fire(){
        this.action(this)
    }
    fun stop() {
        uv_timer_stop(this._ptr).let(UvException::throwIfErrorHappens)
        this.dispose()
    }
}